package mongodump

import (
	"fmt"
	"gitee.com/tym_hmm/mongo-tool/common/log"
	"gitee.com/tym_hmm/mongo-tool/common/signals"
	"gitee.com/tym_hmm/mongo-tool/common/util"
	"strings"
	"time"
)

/**
单个备份数据
用法
	out:= fmt.Sprintf("mgoBack/%s", Time.GetNowTimeDate())
	mgoNode:=&mongoback.MgoBackNode{
		Ip:         mm.ip,
		Port:       mm.port,
		User:       mm.user,
		Pwd:        mm.pwd,
		DataBase:   mm.dataBase,
		Collection: "",
		Out:        out,
	}
	mongoback.NewMgoBack().SetNode(mgoNode).Handler(new(MgoBackListener))
*/
type MgoHandler interface {
	SetNode(node *MgoBackNode) MgoHandler
	Handler(processListener CusProcessListener)
}

/**
备份数据
*/
type MgoBackNode struct {
	Ip         string
	Port       int
	User       string
	Pwd        string
	DataBase   string
	AuthSource string
	Collection string
	Out        string //备份目录
}

/**
mgo命令
*/
type MgoBack struct {
	mgoNode *MgoBackNode
}

func NewMgoBack() MgoHandler {
	return &MgoBack{}
}

func (c *MgoBack) SetNode(node *MgoBackNode) MgoHandler {
	c.mgoNode = node
	return c
}

/**
@param outPath string 备份路径
*/
func (c *MgoBack) Handler(processListener CusProcessListener) {

	if c.mgoNode == nil {
		if processListener != nil {
			processListener.Error("mgo back node empty",c.mgoNode.DataBase, c.mgoNode.Collection)
		} else {
			log.Logvf(log.Always, "mgo back node empty")
		}
		return
	}
	mgoDump := NewMgoDump(c.mgoNode.Ip, c.mgoNode.Port, c.mgoNode.User, c.mgoNode.Pwd)
	mgoDump.SetOut(c.mgoNode.Out)
	if len(strings.TrimSpace(c.mgoNode.AuthSource))>0{
		mgoDump.SetAuthSource(c.mgoNode.AuthSource)
	}
	mgoDump.SetDataBase(c.mgoNode.DataBase)
	mgoDump.SetCollection(c.mgoNode.Collection)
	mgoDump.SetProcessListener(processListener)
	mgoDump.Run()
}

/**
mongoDump备份
*/
type mgoDump struct {
	ip         string
	port       int
	user       string
	pwd        string
	dataBase   string
	authSource string
	collection string
	out        string

	processListener CusProcessListener
}

func NewMgoDump(ip string, port int, user string, pwd string) *mgoDump {
	return &mgoDump{
		ip:         ip,
		port:       port,
		user:       user,
		pwd:        pwd,
		dataBase:   "",
		collection: "",
		out:        "mgoback",
	}
}

/**
设置保存目录
*/
func (md *mgoDump) SetOut(out string) {
	md.out = out
}

/**
设置备份的数据库
*/
func (md *mgoDump) SetDataBase(dataBase string) {
	md.dataBase = dataBase
}

/**
账户验证数据库
*/
func (md *mgoDump)SetAuthSource(authSource string)  {
	md.authSource = authSource
}

/**
设置备份指定的集合
*/
func (md *mgoDump) SetCollection(collectionName string) {
	md.collection = collectionName
}

func (md *mgoDump) SetProcessListener(processListener CusProcessListener) {
	md.processListener = processListener
}

/**
解析地址
*/
func (md *mgoDump) parseUri() string {
	var uri string
	if len(strings.TrimSpace(md.user)) > 0 {
		uri = fmt.Sprintf("mongodb://%s:%s@%s:%d", md.user, md.pwd, md.ip, md.port)
	} else {
		uri = fmt.Sprintf("mongodb://%s:%d", md.ip, md.port)
	}
	return uri
}

func (md *mgoDump) Run() {
	uri := md.parseUri()
	args := []string{}
	args = append(args, uri)
	opts, err := ParseOptions(args, "built-without-version-string", "build-without-git-commit")

	if err != nil {
		if md.processListener != nil {
			md.processListener.Error(fmt.Sprintf("error parsing command line options: %s", err.Error()), md.dataBase, md.collection)
		} else {
			log.Logvf(log.Always, "error parsing command line options: %s", err.Error())
			log.Logvf(log.Always, util.ShortUsage("mongodump"))
		}
		return
	}
	if len(strings.TrimSpace(md.authSource))>0{
		opts.Auth.Source = md.authSource
	}
	opts.Out = md.out
	if len(strings.TrimSpace(md.dataBase)) > 0 {
		opts.DB = md.dataBase
		if len(strings.TrimSpace(md.collection)) > 0 {
			opts.Collection = md.collection
		}
	}

	// verify uri options and log them
	opts.URI.LogUnsupportedOptions()

	// kick off the progress bar manager
	//progressManager := progress.NewBarWriter(log.Writer(0), progressBarWaitTime, progressBarLength, false)
	//progressManager.Start()
	//defer progressManager.Stop()

	progressManager := NewCusBarWriter(log.Writer(0), time.Second*3, 0, false, md.processListener)
	progressManager.Start()
	defer progressManager.Stop()

	dump := MongoDump{
		ToolOptions:     opts.ToolOptions,
		OutputOptions:   opts.OutputOptions,
		InputOptions:    opts.InputOptions,
		ProgressManager: progressManager,
	}

	finishedChan := signals.HandleWithInterrupt(dump.HandleInterrupt)
	defer close(finishedChan)

	if err = dump.Init(); err != nil {
		if md.processListener != nil {
			md.processListener.Error(fmt.Sprintf("Failed: %v", err), md.dataBase, md.collection)
		} else {
			log.Logvf(log.Always, "Failed: %v", err)
		}
		return
	}
	if md.processListener!=nil{
		md.processListener.Start(md.dataBase, md.collection)
	}
	if err = dump.Dump(); err != nil {
		if md.processListener != nil {
			md.processListener.Error(fmt.Sprintf("Failed: %v", err),  md.dataBase, md.collection)
		} else {
			log.Logvf(log.Always, "Failed: %v", err)
		}
	}else{
		if md.processListener!=nil{
			md.processListener.Complete(md.dataBase, md.collection)
		}
	}

}
